#include "define.h"
#include <EEPROM.h>

#define Max7219_pinDINH PORTD |=  _BV(2)
#define Max7219_pinDINL PORTD &= ~_BV(2)
#define Max7219_pinDINO DDRD  |=  _BV(2)
#define Max7219_pinCSH  PORTD |=  _BV(3)
#define Max7219_pinCSL  PORTD &= ~_BV(3)
#define Max7219_pinCSO  DDRD  |=  _BV(3)
#define Max7219_pinCLKH PORTD |=  _BV(4)
#define Max7219_pinCLKL PORTD &= ~_BV(4)
#define Max7219_pinCLKO DDRD  |=  _BV(4)


#define DDR_SCL  DDRB
#define PORT_SCL PORTB
#define BIT_SCL _BV(1)

#define DDR_SDA  DDRB
#define PORT_SDA PORTB
#define PIN_SDA  PINB
#define BIT_SDA _BV(0)


#define DDR_BTN  DDRB
#define PORT_BTN PORTB
#define PIN_BTN  PINB
#define BIT_BTN _BV(2)

#define SCL_H         DDR_SCL &=~ BIT_SCL
#define SCL_L         PORT_SCL &= ~BIT_SCL; DDR_SCL |= BIT_SCL

#define SDA_H         DDR_SDA &=~ BIT_SDA
#define SDA_L         PORT_SDA &= ~BIT_SDA; DDR_SDA |= BIT_SDA
#define SDA_read      PIN_SDA & BIT_SDA



//01111110
//habcdefg
// a
//f b
// g 
//e c
// d h
PROGMEM prog_uint8_t conv[] = {
  //  0     1     2     3     4     5     6     7     8     9     A     B     C     D     E     F    -     
//~0xC0,~0xF9,~0xA4,~0xB0,~0x99,~0x92,~0x82,~0xF8,~0x80,~0x90,~0x88,~0x83,~0xC6,~0xA1,~0x86,~0x8E    16    17
   0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B, 0x77, 0x1F, 0x4E, 0x3D, 0x4F, 0x47, 0x01, 0x00
};


void Write_Max7219_byte(uint8_t DATA)
{
  uint8_t i;
  for(i=8;i>=1;i--)
  {
    Max7219_pinCLKL;
    I2C_delay();
    if(DATA&0x80){
      Max7219_pinDINH;
    }else{
      Max7219_pinDINL;
    }
    DATA=DATA<<1;
    Max7219_pinCLKH;
    I2C_delay();
  }
}
void Write_Max7219(uint8_t address,uint8_t dat)
{ 
  Max7219_pinCSL;
  Write_Max7219_byte(address);           //写入地址，即数码管编号
  Write_Max7219_byte(dat);               //写入数据，即数码管显示数字 
  Max7219_pinCSH;
}
void Init_MAX7219()
{
  Max7219_pinCLKO;
  Max7219_pinCSO ;
  Max7219_pinDINO;
  Write_Max7219(0x09, 0x00);       //译码方式：BCD码
  Write_Max7219(0x0a, 0x03);       //亮度 
  Write_Max7219(0x0b, 0x07);       //扫描界限；8个数码管显示
  Write_Max7219(0x0c, 0x01);       //掉电模式：0，普通模式：1
  Write_Max7219(0x0f, 0x00);       //显示测试：1；测试结束，正常显示：0
}

void SetData_Max7219(uint8_t d0,uint8_t d1,uint8_t d2,uint8_t d3){
  Write_Max7219(1,pgm_read_byte_near(conv+ ( d0&0x0F     ) ) );
  Write_Max7219(2,pgm_read_byte_near(conv+ ((d0&0xF0)>>4 ) ) );
  Write_Max7219(3,pgm_read_byte_near(conv+ ( d1&0x0F     ) ) );
  Write_Max7219(4,pgm_read_byte_near(conv+ ((d1&0xF0)>>4 ) ) );
  Write_Max7219(5,pgm_read_byte_near(conv+ ( d2&0x0F     ) ) );
  Write_Max7219(6,pgm_read_byte_near(conv+ ((d2&0xF0)>>4 ) ) );
  Write_Max7219(7,pgm_read_byte_near(conv+ ( d3&0x0F     ) ) );
  Write_Max7219(8,pgm_read_byte_near(conv+ ((d3&0xF0)>>4 ) ) );
}

PROGMEM prog_uint32_t num10s[] = {
1000000,
100000,
10000,
1000,
100,
10,
1,
};

void SendFloat(float val)
{
	uint32_t num;
	if(val>0){
		Write_Max7219(8,pgm_read_byte_near(conv+( 0x11     ) ) );
		num	= (uint32_t)(val*100.0);
	}else{
		Write_Max7219(8,pgm_read_byte_near(conv+( 0x10     ) ) );
		num	= (uint32_t)(val*-100.0);
	}
	
	uint8_t pos = 7;
	for(uint8_t idx = 0; idx < 8 ; idx++)
	{
		uint8_t outNum = 0;
		uint32_t CmpNum = pgm_read_dword_near(num10s + idx);
		for(uint8_t i = 0; i < 10 ; i++)
		{
			if(num>=CmpNum)
			{
				num -= CmpNum;
				outNum++;
			}
			else
			{
				break;
			}
		}

		Write_Max7219(pos,(pos==3?0x80:0x00)+pgm_read_byte_near(conv+ outNum ) );
		pos--;
		//SerialSend('0' + outNum);
	}
}























uint8_t i2cErrorCount;

static void I2C_delay(void)
{
  for(uint8_t i=0;i<16;i++)//6 is stable
  {
    volatile uint8_t v=0;
    v++;
  }
}

static bool I2C_Start(void)
{
    SDA_H;
    SCL_H;
    I2C_delay();
    if (!SDA_read) {
        return false;
    }
    SDA_L;
    I2C_delay();
    if (SDA_read) {
        return false;
    }
    SDA_L;
    I2C_delay();
    return true;
}

static void I2C_Stop(void)
{
    SCL_L;
    I2C_delay();
    SDA_L;
    I2C_delay();
    SCL_H;
    I2C_delay();
    SDA_H;
    I2C_delay();
}

static void I2C_Ack(void)
{
    SCL_L;
    I2C_delay();
    SDA_L;
    I2C_delay();
    SCL_H;
    I2C_delay();
    SCL_L;
    I2C_delay();
}

static void I2C_NoAck(void)
{
    SCL_L;
    I2C_delay();
    SDA_H;
    I2C_delay();
    SCL_H;
    I2C_delay();
    SCL_L;
    I2C_delay();
}

static bool I2C_WaitAck(void)
{
    SCL_L;
    I2C_delay();
    SDA_H;
    I2C_delay();
    SCL_H;
    I2C_delay();
    if (SDA_read) {
        SCL_L;
        return false;
    }
    SCL_L;
    return true;
}

static void I2C_SendByte(uint8_t byte)
{
    uint8_t i = 8;
    while (i--) {
        SCL_L;
        I2C_delay();
        if (byte & 0x80) {
            SDA_H;
        }
        else {
            SDA_L;
        }
        byte <<= 1;
        I2C_delay();
        SCL_H;
        I2C_delay();
    }
    SCL_L;
}

static uint8_t I2C_ReceiveByte(void)
{
    uint8_t i = 8;
    uint8_t byte = 0;

    SDA_H;
    while (i--) {
        byte <<= 1;
        SCL_L;
        I2C_delay();
        SCL_H;
        I2C_delay();
        if (SDA_read) {
            byte |= 0x01;
        }
    }
    SCL_L;
    return byte;
}

bool i2cRead(uint8_t addr, uint8_t reg, uint8_t len, uint8_t *buf)
{
    if (!I2C_Start()) {
        return false;
    }
    I2C_SendByte(addr << 1 | I2C_Direction_Transmitter);
    if (!I2C_WaitAck()) {
        I2C_Stop();
        i2cErrorCount++;
        return false;
    }
    I2C_SendByte(reg);
    I2C_WaitAck();
    I2C_Start();
    I2C_SendByte(addr << 1 | I2C_Direction_Receiver);
    I2C_WaitAck();
    while (len) {
        *buf = I2C_ReceiveByte();
        if (len == 1) {
            I2C_NoAck();
        }
        else {
            I2C_Ack();
        }
        buf++;
        len--;
    }
    I2C_Stop();
    return true;
}

bool i2cWrite(uint8_t addr, uint8_t reg, uint8_t data)
{

    if (!I2C_Start()) {
        return false;
    }
    I2C_SendByte(addr << 1 | I2C_Direction_Transmitter);
    if (!I2C_WaitAck()) {
        I2C_Stop();
        i2cErrorCount++;
        return false;
    }
    I2C_SendByte(reg);
    I2C_WaitAck();
    I2C_SendByte(data);
    I2C_WaitAck();
    I2C_Stop();
    return true;
}

bool bmp280ReadRegister(uint8_t reg, uint8_t length, uint8_t *data)
{
    const bool ack = i2cRead(BMP280_I2C_ADDR, reg, length, data);
    return ack;
}

bool bmp280WriteRegister(uint8_t reg, uint8_t data)
{
    const bool ack = i2cWrite(BMP280_I2C_ADDR, reg, data);
    return ack;
}

//=======================================================================================================================================

#define PRESSURE_SAMPLE_COUNT (baro_sample_count - 1)

uint8_t baro_sample_count = 21;

typedef struct bmp280_calib_param_s {
    uint16_t dig_T1; /* calibration T1 data */
    int16_t dig_T2; /* calibration T2 data */
    int16_t dig_T3; /* calibration T3 data */
    uint16_t dig_P1; /* calibration P1 data */
    int16_t dig_P2; /* calibration P2 data */
    int16_t dig_P3; /* calibration P3 data */
    int16_t dig_P4; /* calibration P4 data */
    int16_t dig_P5; /* calibration P5 data */
    int16_t dig_P6; /* calibration P6 data */
    int16_t dig_P7; /* calibration P7 data */
    int16_t dig_P8; /* calibration P8 data */
    int16_t dig_P9; /* calibration P9 data */
    int32_t t_fine; /* calibration t_fine data */
} bmp280_calib_param_t;

bmp280_calib_param_t bmp280_cal;

float baroPressure = 0;


bool bmp280Detect()
{
    delay(20);

    uint8_t bmp280_chip_id = 0;
    
    bmp280ReadRegister(BMP280_CHIP_ID_REG, 1, &bmp280_chip_id);  /* read Chip Id */

    if (bmp280_chip_id != BMP280_DEFAULT_CHIP_ID) {
      Serial.println("error");
      return false;
    }

    // read calibration
    bmp280ReadRegister(BMP280_TEMPERATURE_CALIB_DIG_T1_LSB_REG, 24, (uint8_t *)&bmp280_cal);

    return true;
}



//---------------------------------------------------------------------------------------------------------------------------------------------------------------------

int32_t bmp280_up = 0;
int32_t bmp280_ut = 0;


void start_up()
{
    // start measurement
    // set oversampling + power mode (forced), and start sampling
    bmp280WriteRegister(BMP280_CTRL_MEAS_REG, BMP280_MODE);
}

void get_up()
{
    uint8_t data[BMP280_DATA_FRAME_SIZE];

    // read data from sensor
    bmp280ReadRegister(BMP280_PRESSURE_MSB_REG, BMP280_DATA_FRAME_SIZE, data);
    bmp280_up = (int32_t)((((uint32_t)(data[0])) << 12) | (((uint32_t)(data[1])) << 4) | ((uint32_t)data[2] >> 4));
    bmp280_ut = (int32_t)((((uint32_t)(data[3])) << 12) | (((uint32_t)(data[4])) << 4) | ((uint32_t)data[5] >> 4));
}

// Returns temperature in DegC, resolution is 0.01 DegC. Output value of "5123" equals 51.23 DegC
// t_fine carries fine temperature as global value
int32_t bmp280_compensate_T(int32_t adc_T)
{
    int32_t var1, var2, T;

    var1 = ((((adc_T >> 3) - ((int32_t)bmp280_cal.dig_T1 << 1))) * ((int32_t)bmp280_cal.dig_T2)) >> 11;
    var2  = (((((adc_T >> 4) - ((int32_t)bmp280_cal.dig_T1)) * ((adc_T >> 4) - ((int32_t)bmp280_cal.dig_T1))) >> 12) * ((int32_t)bmp280_cal.dig_T3)) >> 14;
    bmp280_cal.t_fine = var1 + var2;
    T = (bmp280_cal.t_fine * 5 + 128) >> 8;

    return T;
}

// Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
// Output value of "24674867" represents 24674867/256 = 96386.2 Pa = 963.862 hPa
uint32_t bmp280_compensate_P(int32_t adc_P)
{
    int64_t var1, var2, p;
    var1 = ((int64_t)bmp280_cal.t_fine) - 128000;
    var2 = var1 * var1 * (int64_t)bmp280_cal.dig_P6;
    var2 = var2 + ((var1*(int64_t)bmp280_cal.dig_P5) << 17);
    var2 = var2 + (((int64_t)bmp280_cal.dig_P4) << 35);
    var1 = ((var1 * var1 * (int64_t)bmp280_cal.dig_P3) >> 8) + ((var1 * (int64_t)bmp280_cal.dig_P2) << 12);
    var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)bmp280_cal.dig_P1) >> 33;
    if (var1 == 0) return 0;
    p = 1048576 - adc_P;
    p = (((p << 31) - var2) * 3125) / var1;
    var1 = (((int64_t)bmp280_cal.dig_P9) * (p >> 13) * (p >> 13)) >> 25;
    var2 = (((int64_t)bmp280_cal.dig_P8) * p) >> 19;
    p = ((p + var1 + var2) >> 8) + (((int64_t)bmp280_cal.dig_P7) << 4);
    return (uint32_t)p;
}

int32_t baroAlt = 0;

float calculate()
{
    // calculate
    int32_t t;
    uint32_t p;
    t = bmp280_compensate_T(bmp280_ut);
    p = bmp280_compensate_P(bmp280_up);

    return (p / 256);
}


void setup(){
  DDR_BTN &= ~BIT_BTN;
  PORT_BTN |= BIT_BTN;
  
  Serial.begin(9600);
  Serial.setTimeout(10000000);
  Serial.println();
  
  Init_MAX7219();
  if(!bmp280Detect()){
    while(1);
  }
  Serial.println("ok");
  delay(50);
  start_up();
  delay(50);
}


float baroCalculateAltitude()
{
  float tempa = baroPressure / 101325.0f;
  float tempb = pow(tempa, 0.190295f);
  return (1.0f - tempb) * 4433000.0f; // in cm
}

union A{
  uint8_t b[4];
  float f;
};

float readEEPROM(){
  union A a;
  a.b[0] = EEPROM.read(1010);
  a.b[1] = EEPROM.read(1011);
  a.b[2] = EEPROM.read(1012);
  a.b[3] = EEPROM.read(1013);
  return a.f;
}

void writeEEPROM(float val){
  union A a;
  a.f = val;
  EEPROM.write(1010, a.b[0]);
  EEPROM.write(1011, a.b[1]);
  EEPROM.write(1012, a.b[2]);
  EEPROM.write(1013, a.b[3]);
}

float accu[8];
uint8_t index = 0;
uint8_t btn_down = 0;
void loop()
{
  float zero = readEEPROM();

  get_up();
  baroPressure = calculate();
  baroAlt = baroCalculateAltitude();
  accu[index] = baroAlt;
  index++;
  index&=7;

  float avg = 0;
  for(uint8_t i = 0;i<8;i++){
    avg += accu[i];
  }
  avg /= 8;
  
  SendFloat((avg - zero)/100);

  if(!(PIN_BTN & BIT_BTN)){
    if(!btn_down){
      btn_down = 1;
      writeEEPROM(avg);
    }
  }else{
    btn_down = 0;
  }

  Serial.print(baroAlt);
  Serial.print(", ");
  Serial.println(avg);
  
  start_up();
  delay(50);//23
}
